package lib

import (
	"context"
	"fmt"
	"github.com/go-redis/redis/v8"
	"time"
)

type Locker struct {
	key        string
	expiration time.Duration
	ISbool     bool
}

func NewLocker(key string) *Locker {
	return &Locker{key: key, expiration: time.Second * 30}
}
func NewLockerWithTTL(key string, expir time.Duration) *Locker {
	return &Locker{key: key, expiration: expir}
}
func (this *Locker) Lock() *Locker {
	boolcmd := redisClient.SetNX(context.Background(), this.key, "1", this.expiration)
	if ok, err := boolcmd.Result(); err != nil || !ok {
		panic(fmt.Sprintf("lock error with key:%s", this.key))
	}
	this.expendtime()
	return this
}

const incrLua = `
if redis.call('get', KEYS[1]) == ARGV[1] then
  return redis.call('expire', KEYS[1],ARGV[2]) 				
 else
   return '0' 					
end`

func (this *Locker) Unlock() {
	redisClient.Del(context.Background(), this.key)
	this.ISbool = true
}

//重新设置后期时间
func (this *Locker) Rexpire() {
	script := redis.NewScript(incrLua)
	cmd := script.Run(context.Background(), redisClient, []string{this.key}, 1, this.expiration.Seconds())
	ok, err := cmd.Result()
	//cmd := redisClient.Expire(context.Background(), this.key, this.expiration)//不是原子操作
	fmt.Printf("key:%s,续期结果为：%v,%v", this.key, ok, err)
}

//定时任务执行
func (this *Locker) expendtime() {
	sleepTime := this.expiration.Seconds() * 2 / 3
	go func() {
		for {
			time.Sleep(time.Second * time.Duration(sleepTime))
			if this.ISbool {
				break
			}
			this.Rexpire()
		}
	}()
}